"""
微信公众平台API测试

测试WeChatAPI类的功能，使用mock模拟请求，避免实际调用API。
"""

import unittest
from unittest.mock import patch, MagicMock
import json
from cn_api_adapters import WeChatAPI
from cn_api_adapters.common.exceptions import APIError, AuthenticationError


class TestWeChatAPI(unittest.TestCase):
    """测试WeChatAPI类的功能"""
    
    def setUp(self):
        """设置测试环境"""
        self.app_id = "test_app_id"
        self.app_secret = "test_app_secret"
        self.api = WeChatAPI(
            app_id=self.app_id,
            app_secret=self.app_secret,
            debug=False
        )
    
    @patch('cn_api_adapters.wechat.wechat_api.WeChatAPI._request')
    def test_get_access_token_success(self, mock_request):
        """测试获取AccessToken成功的情况"""
        # 模拟成功响应
        mock_response = {
            "access_token": "mock_access_token",
            "expires_in": 7200
        }
        mock_request.return_value = mock_response
        
        # 获取access_token
        token = self.api.get_access_token()
        
        # 验证结果
        self.assertEqual(token, "mock_access_token")
        mock_request.assert_called_once_with(
            "GET",
            "https://api.weixin.qq.com/cgi-bin/token",
            params={
                "grant_type": "client_credential",
                "appid": self.app_id,
                "secret": self.app_secret
            }
        )
    
    @patch('cn_api_adapters.wechat.wechat_api.WeChatAPI._request')
    def test_access_token_property(self, mock_request):
        """测试access_token属性"""
        # 模拟成功响应
        mock_response = {
            "access_token": "mock_access_token",
            "expires_in": 7200
        }
        mock_request.return_value = mock_response
        
        # 通过属性获取access_token
        token = self.api.access_token
        
        # 验证结果
        self.assertEqual(token, "mock_access_token")
    
    @patch('cn_api_adapters.wechat.wechat_api.WeChatAPI._request')
    def test_get_access_token_failure(self, mock_request):
        """测试获取AccessToken失败的情况"""
        # 模拟失败响应
        mock_request.side_effect = APIError("invalid credential")
        
        # 验证抛出异常
        with self.assertRaises(APIError):
            self.api.get_access_token()
    
    @patch('cn_api_adapters.wechat.wechat_api.WeChatAPI._request')
    @patch('cn_api_adapters.wechat.wechat_api.WeChatAPI.get_access_token')
    def test_send_template_message(self, mock_get_token, mock_request):
        """测试发送模板消息"""
        # 模拟token
        mock_get_token.return_value = "mock_token"
        
        # 模拟成功响应
        mock_request.return_value = {"errcode": 0, "errmsg": "ok"}
        
        # 发送模板消息
        template_data = {
            "touser": "test_openid",
            "template_id": "test_template_id",
            "data": {
                "first": {"value": "测试消息", "color": "#173177"},
                "keyword1": {"value": "测试内容", "color": "#173177"}
            }
        }
        
        result = self.api.send_template_message(**template_data)
        
        # 验证结果
        self.assertEqual(result, {"errcode": 0, "errmsg": "ok"})
        mock_request.assert_called_once_with(
            "POST",
            "https://api.weixin.qq.com/cgi-bin/message/template/send",
            params={"access_token": "mock_token"},
            json=template_data
        )
    
    @patch('cn_api_adapters.wechat.wechat_api.WeChatAPI._request')
    @patch('cn_api_adapters.wechat.wechat_api.WeChatAPI.get_access_token')
    def test_create_menu(self, mock_get_token, mock_request):
        """测试创建自定义菜单"""
        # 模拟token
        mock_get_token.return_value = "mock_token"
        
        # 模拟成功响应
        mock_request.return_value = {"errcode": 0, "errmsg": "ok"}
        
        # 创建菜单
        menu_data = {
            "button": [
                {
                    "type": "click",
                    "name": "测试按钮",
                    "key": "TEST_KEY"
                }
            ]
        }
        
        result = self.api.create_menu(menu_data)
        
        # 验证结果
        self.assertEqual(result, {"errcode": 0, "errmsg": "ok"})
        mock_request.assert_called_once_with(
            "POST",
            "https://api.weixin.qq.com/cgi-bin/menu/create",
            params={"access_token": "mock_token"},
            json=menu_data
        )
    
    @patch('cn_api_adapters.wechat.wechat_api.WeChatAPI._request')
    @patch('cn_api_adapters.wechat.wechat_api.WeChatAPI.get_access_token')
    def test_get_menu(self, mock_get_token, mock_request):
        """测试获取自定义菜单"""
        # 模拟token
        mock_get_token.return_value = "mock_token"
        
        # 模拟成功响应
        expected_menu = {
            "menu": {
                "button": [
                    {
                        "type": "click",
                        "name": "测试按钮",
                        "key": "TEST_KEY"
                    }
                ]
            }
        }
        mock_request.return_value = expected_menu
        
        # 获取菜单
        result = self.api.get_menu()
        
        # 验证结果
        self.assertEqual(result, expected_menu)
        mock_request.assert_called_once_with(
            "GET",
            "https://api.weixin.qq.com/cgi-bin/menu/get",
            params={"access_token": "mock_token"}
        )
    
    @patch('cn_api_adapters.wechat.wechat_api.WeChatAPI._request')
    @patch('cn_api_adapters.wechat.wechat_api.WeChatAPI.get_access_token')
    def test_delete_menu(self, mock_get_token, mock_request):
        """测试删除自定义菜单"""
        # 模拟token
        mock_get_token.return_value = "mock_token"
        
        # 模拟成功响应
        mock_request.return_value = {"errcode": 0, "errmsg": "ok"}
        
        # 删除菜单
        result = self.api.delete_menu()
        
        # 验证结果
        self.assertEqual(result, {"errcode": 0, "errmsg": "ok"})
        mock_request.assert_called_once_with(
            "GET",
            "https://api.weixin.qq.com/cgi-bin/menu/delete",
            params={"access_token": "mock_token"}
        )
    
    @patch('cn_api_adapters.wechat.wechat_api.WeChatAPI._request')
    @patch('cn_api_adapters.wechat.wechat_api.WeChatAPI.get_access_token')
    def test_get_user_list(self, mock_get_token, mock_request):
        """测试获取用户列表"""
        # 模拟token
        mock_get_token.return_value = "mock_token"
        
        # 模拟成功响应
        expected_users = {
            "total": 2,
            "count": 2,
            "data": {"openid": ["openid1", "openid2"]},
            "next_openid": "openid3"
        }
        mock_request.return_value = expected_users
        
        # 获取用户列表
        result = self.api.get_user_list()
        
        # 验证结果
        self.assertEqual(result, expected_users)
        mock_request.assert_called_once_with(
            "GET",
            "https://api.weixin.qq.com/cgi-bin/user/get",
            params={"access_token": "mock_token"}
        )
    
    @patch('cn_api_adapters.wechat.wechat_api.WeChatAPI._request')
    @patch('cn_api_adapters.wechat.wechat_api.WeChatAPI.get_access_token')
    def test_get_user_info(self, mock_get_token, mock_request):
        """测试获取用户信息"""
        # 模拟token
        mock_get_token.return_value = "mock_token"
        
        # 模拟成功响应
        expected_user = {
            "openid": "test_openid",
            "nickname": "测试用户",
            "sex": 1,
            "language": "zh_CN",
            "city": "深圳",
            "province": "广东",
            "country": "中国",
            "headimgurl": "http://example.com/avatar.jpg",
            "subscribe_time": 1382694957,
            "unionid": "test_unionid"
        }
        mock_request.return_value = expected_user
        
        # 获取用户信息
        result = self.api.get_user_info("test_openid")
        
        # 验证结果
        self.assertEqual(result, expected_user)
        mock_request.assert_called_once_with(
            "GET",
            "https://api.weixin.qq.com/cgi-bin/user/info",
            params={
                "access_token": "mock_token",
                "openid": "test_openid",
                "lang": "zh_CN"
            }
        )
    
    @patch('cn_api_adapters.wechat.wechat_api.WeChatAPI._request')
    @patch('cn_api_adapters.wechat.wechat_api.WeChatAPI.get_access_token')
    def test_create_qrcode_temp(self, mock_get_token, mock_request):
        """测试创建临时二维码"""
        # 模拟token
        mock_get_token.return_value = "mock_token"
        
        # 模拟成功响应
        expected_result = {
            "ticket": "mock_ticket",
            "expire_seconds": 604800,
            "url": "http://example.com/qrcode"
        }
        mock_request.return_value = expected_result
        
        # 创建临时二维码
        result = self.api.create_qrcode(scene_id=123, expire_seconds=604800, is_temp=True)
        
        # 验证结果
        self.assertEqual(result, expected_result)
        mock_request.assert_called_once_with(
            "POST",
            "https://api.weixin.qq.com/cgi-bin/qrcode/create",
            params={"access_token": "mock_token"},
            json={"expire_seconds": 604800, "action_name": "QR_SCENE", "action_info": {"scene": {"scene_id": 123}}}
        )
    
    @patch('cn_api_adapters.wechat.wechat_api.WeChatAPI._request')
    @patch('cn_api_adapters.wechat.wechat_api.WeChatAPI.get_access_token')
    def test_create_qrcode_permanent(self, mock_get_token, mock_request):
        """测试创建永久二维码"""
        # 模拟token
        mock_get_token.return_value = "mock_token"
        
        # 模拟成功响应
        expected_result = {
            "ticket": "mock_ticket",
            "url": "http://example.com/qrcode"
        }
        mock_request.return_value = expected_result
        
        # 创建永久二维码
        result = self.api.create_qrcode(scene_str="test_scene", is_temp=False)
        
        # 验证结果
        self.assertEqual(result, expected_result)
        mock_request.assert_called_once_with(
            "POST",
            "https://api.weixin.qq.com/cgi-bin/qrcode/create",
            params={"access_token": "mock_token"},
            json={"action_name": "QR_LIMIT_STR_SCENE", "action_info": {"scene": {"scene_str": "test_scene"}}}
        )


if __name__ == '__main__':
    unittest.main()